package predictors.co2predictor;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

import objects.predictors.Co2Info;

import predictors.PearsonsCalc;

import database.ConnectionManager;

import utils.DateUtil;
import utils.Utils;

public class CO2PredictorImpl {
	final static long hoursInMillis = 60L * 60L * 1000L;
	final static long weekInMillis = 24 * 7 * hoursInMillis;
	public static DateFormat OUT_DATETIME_FORMAT = new SimpleDateFormat("d/M/yyyy HH:mm:ss");
	
	public static Co2Info GetAvgLowestEmissionDateInTimeRange(int trange)
	throws Exception {
		Date now = new Date();
		return GetAvgLowestEmissionDateInTimeRange(now, new Date(now.getTime() + trange * hoursInMillis));
	}
	public static Co2Info GetAvgLowestEmissionDateInTimeRange(Date start, int trange)
	throws Exception {
		return GetAvgLowestEmissionDateInTimeRange(start, new Date(start.getTime() + trange * hoursInMillis));
	}
	public static Co2Info GetAvgLowestEmissionDateInTimeRange(Date start, Date end)
			throws Exception {
		
		Connection conn = ConnectionManager.ds.getConnection();
		Date min_date = start;
		double min_avg = Double.MAX_VALUE;
		double min_std = 0;
		Date s = new Date(start.getTime() + 2 * hoursInMillis);
		String query = "select co2,timestamp from power_data2 order by id desc limit 1 ";
		PreparedStatement stmt = conn.prepareStatement(query);
		ResultSet rs = stmt.executeQuery();
		rs.first();
		double now = rs.getDouble("co2");
		Date lastweek = new Date(rs.getTimestamp("timestamp").getTime() - weekInMillis);
		query = "select co2 from power_data2 where timestamp = ? ";
		stmt = conn.prepareStatement(query);
		stmt.setTimestamp(1, new java.sql.Timestamp(lastweek.getTime()));
		rs = stmt.executeQuery();
		double diff = 0;
		if(rs.first())	
			diff = now - rs.getDouble("co2");
		Utils.out("\n ------ CO2 Predictor ------");
		Utils.out("+ Diff is: "+diff);
		Utils.out("+ Starting search...");
		while (start.compareTo(end) <= 0) {
			
			int time = start.getHours();
			int day = start.getDay();
			//System.out.println("start is "+OUT_DATETIME_FORMAT.format(start)+" end is "+OUT_DATETIME_FORMAT.format(end)+" "+time+" "+day);
			query = "select co2 from power_data2 where timenum = ? and daynum = ?";
			stmt = conn.prepareStatement(query);
			stmt.setInt(1, time);
			stmt.setInt(2, day);
			rs = stmt.executeQuery();
			double tot_instances = DateUtil.getRowCount(rs);
			double tot = 0;
			double std_dev = 0;
			while (rs.next()) {
				tot += rs.getDouble("co2");
			}
			double avg = tot / tot_instances;
			Utils.out("===============");
			Utils.out("+ Start: "+OUT_DATETIME_FORMAT.format(start)+" End: "+OUT_DATETIME_FORMAT.format(end));
			Utils.out("+ Avg is: "+Utils.f.format(avg));
			Utils.out("===============\n");
			if (avg < min_avg) {
				min_date = start;
				min_avg = avg;
				rs.beforeFirst();
				while (rs.next()) {
					double val = rs.getDouble("co2") - avg;
					std_dev += val*val;
				}
				std_dev /= tot_instances;
				std_dev = Math.sqrt(std_dev);
				min_std = std_dev;
			}
			start = new Date(start.getTime() + hoursInMillis);
		}
		double pears = -2;
		Utils.out("+ Done searching.");
		if(min_date.compareTo(s) <= 0)
		{
			Utils.out("+ Calculating pearsons coeff...");
			pears = PearsonsCalc.GetPearsons();
		}
		else
		{
			Utils.out("+ Pearsons coeff not calculated (default: -2).");
		}
		Utils.out(" ===========================");
		Utils.out("+ Lowest avg: "+Utils.f.format(min_avg));
		Utils.out("+ Lowest avg+diff: "+Utils.f.format(min_avg+diff));
		Utils.out("+ Datetime: "+OUT_DATETIME_FORMAT.format(min_date));
		Utils.out("+ Pearsons coeff: "+Utils.f.format(pears));
		Utils.out(" ===========================\n\n");
		conn.close();
		return new Co2Info(min_avg+diff,min_std,min_date,pears);
	}

}
